Skip to content

Feat: Implemented Storybook Interface for Dispute Raise ModaL - #356

Merged
godamongstmen897 merged 156 commits into
Goldii-locks:mainfrom
She-ge:feat/338-dispute-raise-modal-stories
Aug 31, 2026
Merged

Feat: Implemented Storybook Interface for Dispute Raise ModaL#356
godamongstmen897 merged 156 commits into
Goldii-locks:mainfrom
She-ge:feat/338-dispute-raise-modal-stories

Conversation

@She-ge

@She-ge She-ge commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

closes #338

vicajohn and others added 30 commits August 27, 2026 06:26
- Replace hardcoded empty message with EmptyStateCard component
- Display briefcase icon for job-related context
- Show descriptive title and explanation text
- Include role badges (Client, Freelancer, Arbiter) showing available participation options
- Add comprehensive test coverage with 16 test cases
- Ensure proper accessibility with region landmarks and aria-labels
- Validates placeholder display under empty data states
…, desktop

- Add responsive padding and spacing (px-3 sm:px-6) for mobile-first approach
- Implement responsive typography scaling (text-xl sm:text-2xl md:text-3xl)
- Stack layout vertically on mobile, horizontal on tablet/desktop
- Apply responsive grid layouts (grid-cols-1 sm:grid-cols-2 lg:grid-cols-3)
- Make search form full-width on mobile, inline on tablet+
- Add responsive gaps and margins throughout
- Implement horizontal overflow handling for pagination on mobile
- Reduce button padding and font sizes on mobile viewports
- Add comprehensive responsive design test suite with 20 test cases
- Validate layout at mobile (< 640px), tablet (640-1024px), desktop (> 1024px)
…yling

- Add focus-visible ring-2 styling on all interactive elements (indigo-500)
- Implement hover state transitions with smooth animations (transition-all duration-200)
- Add active state styling for button press feedback
- Style disabled buttons with opacity-50 and cursor-not-allowed
- Prevent hover effects on disabled buttons (disabled:hover:bg-gray-900)
- Apply ring-offset for focus states on dark background (ring-offset-gray-950)
- Use inset focus ring on job expand buttons for better UX
- Add focus-visible:outline-none to remove browser defaults
- Implement smooth transitions on all state changes
- Add comprehensive test suite with 25 test cases validating:
  - Search input focus and hover states
  - Search button focus, hover, and active states
  - Role filter button states and transitions
  - Job expand button interactive states
  - Pagination button states and disabled styling
  - Accessibility compliance and transitions
Implements the app dark/light theme toggle as a keyboard-operable,
ARIA-compliant switch (role=switch, aria-checked, aria-label) that
persists the chosen theme to localStorage and applies it to the document
root. Adds React Testing Library tests verifying node rendering,
accessible state, theme application, keyboard operation and persistence.

Closes Goldii-locks#319
Implements the navbar alert bell badge as a keyboard-operable
(role=button) disclosure with ARIA compliance (Goldii-locks#320): accessible name,
aria-haspopup/aria-expanded/aria-controls, aria-live announcement
regions, aria-hidden on decorative glyphs, focus-visible rings and
design-token contrast.

Adds field error indicators and alerts (Goldii-locks#324): validation field configs
render role=alert error text that toggles as validation triggers, wired
via aria-describedby and counted toward the unread badge.

Adds React Testing Library tests covering both requirements.

Closes Goldii-locks#320
Closes Goldii-locks#324
Stack the stat grid and content rows to a single column on mobile,
two on tablet, three on desktop, and use responsive padding/spacing
so LoadingSkeleton scales cleanly at every breakpoint.

Closes Goldii-locks#275
Fade the skeleton in on mount (animate-fade-in) instead of popping in
abruptly, and stagger each placeholder bar's pulse animation-delay so
the loading state reads as a smooth wave rather than a flat blink.

Closes Goldii-locks#278
Replace the bare "No jobs found" line with a reusable EmptyState
component (icon, heading, supporting copy) shown once loading
finishes with zero jobs for the connected wallet.

Closes Goldii-locks#276
… mobile

Cap the skeleton's height on small viewports and let it scroll
internally (overscroll-contain) instead of pushing surrounding
controls off-screen, while keeping the wrapper free of fixed/absolute
positioning so it never traps taps on other elements.

Closes Goldii-locks#279
Closes Goldii-locks#240, Goldii-locks#238, Goldii-locks#236, Goldii-locks#332.

wallet_disconnect_handler (Goldii-locks#240, Goldii-locks#238, Goldii-locks#236)
- Goldii-locks#240 Gas estimation warnings: checkDisconnectSimulationFeeWarning inspects
  a Soroban simulation result and flags fees above the 1_000_000 stroop
  (0.1 XLM) bound, plus simulation errors and non-finite fee estimates.
  Simulation errors take precedence over the fee check, since a failed
  simulation's reported fee is not trustworthy. Surfaced by
  WalletDisconnectGasWarningBanner.
- Goldii-locks#238 Loading spinner: a counter-based loader lifecycle
  (start/end/reset/subscribe/withWalletDisconnectLoader) so overlapping
  disconnects do not hide the overlay early, clamped at zero so an
  unbalanced end cannot wedge it open. disconnectWalletWithCheck now runs
  entirely inside the lifecycle, so the spinner clears on every exit path
  (success, missing wallet, throw). Surfaced by
  WalletDisconnectLoaderOverlay.
- Goldii-locks#236 Network mismatch: checkDisconnectNetworkMatch compares the wallet
  chain against the app chain, normalising bare labels, the public/test
  aliases, and full Stellar passphrases, since wallets report them
  interchangeably. An unrecognised network is reported as a mismatch rather
  than silently ignored. Surfaced by WalletDisconnectNetworkWarningBar.

dispute_raise_modal (Goldii-locks#332)
- The module did not exist; added app/lib/dispute_raise_modal.ts and
  DisputeRaiseModal alongside it. Sizing is mobile-first: a full-bleed
  bottom sheet with stacked full-width actions on phones, a centered
  sm:max-w-lg dialog on tablets, and a lg:max-w-2xl panel on desktop. The
  summary grid collapses to one column below sm: and long addresses wrap,
  so nothing forces horizontal scroll at 375/414px. Touch targets meet the
  44px minimum used elsewhere in the repo.
- useDisputeViewport uses useSyncExternalStore rather than an effect plus
  setState, avoiding the cascading render the react-hooks
  set-state-in-effect rule targets.

Tests: 4 new files, 204 cases covering fee bounds and simulation errors,
spinner toggling on start/end across every exit path, network mismatch
detection and warning-bar rendering, and modal layout at 320-1920px
including live resize. Type-check and lint clean.

Pre-existing failures unchanged and unrelated: 4 cases in
freighter_multisig_hook.test.ts (invalid XDR fixtures) and 2 files that
cannot collect due to a @stellar/freighter-api CJS/ESM interop error via
WalletContext. Both reproduce on a clean checkout.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Add flex-wrap and min-w-0 to nav items container so items wrap
  instead of overflowing horizontally on narrow viewports (iPhone SE)
- Add relative z-10 to <nav> to establish a stacking context above
  non-overlay page content
- Replace inline wallet span + disconnect button with WalletBadge
  component (adds proper a11y attrs and shrink-0 for mobile)
- Tighten nav padding on mobile (px-4 sm:px-6, py-3 sm:py-4)
- Remove now-unused short() address helper from Navbar
- Add WalletBadge.test.tsx: 18 tests covering interactive element
  presence, click handler firing, and desktop regression at common
  mobile viewport heights (375x568, 375x667, 414x736)
godamongstmen897 and others added 28 commits August 31, 2026 14:40
…classes

One conflict on the job row button in app/dashboard/page.tsx. Both
sides styled the same element, so the resolution keeps every class
either side contributed:

  responsive padding      px-3 sm:px-5 py-3 sm:py-4   (from Goldii-locks#304)
  press feedback          active:scale-[0.99]         (from main)
  focus ring              focus-visible:ring-2/-inset/-indigo-500 (this branch)

Transition widened to transition-all duration-200 (this branch's value)
rather than transition-colors -- the branch adds a focus ring, and
main's side adds a scale, neither of which transition-colors animates.

lint 0 errors / tsc 0 errors / 1903 tests passing / build OK
…ractive-states

Feat/dashboard interactive states
…k-switcher-mobile-nav

fix(Goldii-locks#316): Handle mobile viewports navigation styling in dark_mode_switcher
… semantics

Two conflicts in app/dashboard/page.tsx, both resolved by keeping every
attribute either side contributed:

- Error alert: the branch's styled box and aria-live="assertive" plus
  main's data-testid="dashboard-error-alert" and animate-shake.
- Expanded panel: the branch's id/role="region"/aria-label plus main's
  data-testid="dashboard-expanded-panel" and animate-fade-in.

Beyond the conflicts, this branch changes the accessible names and roles
of controls that sibling suites already query, and its copy of
dashboard-interactive-states.test.tsx is identical to main's -- so those
queries were never updated to match. Retargeted them:

  filter controls   role=button -> role=tab (the branch wraps them in a
                    tablist), aria-pressed -> aria-selected
  search submit     name "Search" -> "Submit search query"
  pagination        name "Previous"/"Next" -> /Previous page/i, /Next page/i

Touched dashboard-interactive-states, dashboard-responsive and
loading-skeleton-mobile. Every assertion still checks what it did
before -- only the queries locating the elements changed.

lint 0 errors / tsc 0 errors / 1945 tests passing / build OK
…ssibility-compliance

Feat/dashboard accessibility compliance
…ification-bell-responsive

fix(Goldii-locks#322): Add responsive sizing layouts on notification_bell
…he timeout call

git aligned two unrelated function bodies here: the branch's rewritten
disconnectWalletWithCheck against main's generic
withWalletDisconnectLoader, so the raw conflict would have replaced the
loader's body with disconnect logic referencing disconnectFn, options
and walletId -- none of which are in that scope.

Resolved by putting each change where it belongs:

- withWalletDisconnectLoader keeps main's body.
- disconnectWalletWithCheck routes through the branch's new
  runWalletDisconnectWithTimeout helper, still inside main's
  withWalletDisconnectLoader wrapper.

The branch predates the loader lifecycle work (Goldii-locks#238), which is why its
side had dropped that wrapper -- keeping both preserves the timeout
bounds this PR is for and the overlay behaviour already on main.

lint 0 errors / tsc 0 errors / 1948 tests passing / build OK
…nnect-timeout-bounds

Feat: wallet disconnect handler
No textual conflict once Goldii-locks#357 (this branch's parent) landed on main --
GitHub's cached mergeability was stale and its update-branch call
reported a conflict that a local three-way merge does not reproduce.
Merging main in here refreshes the head so CI runs against current main.

lint 0 errors / tsc 0 errors / 1949 tests passing / build OK
…dline-badge

Feat: Notification badge for milestones
…eachable

Three conflicts in wallet_disconnect_handler.ts, all from this branch
predating the loader lifecycle work (Goldii-locks#238) and the timeout bounds (Goldii-locks#357):

- Doc comment: kept both notes.
- "Not installed" branch: main's structure (it now sits inside the
  withWalletDisconnectLoader closure, hence the deeper indent) plus this
  branch's removeActiveKey call.
- Third hunk was git aligning this branch's disconnectWalletWithCheck
  body onto main's generic withWalletDisconnectLoader again, as in Goldii-locks#357.
  Kept main's loader body and applied the branch's success-path
  removeActiveKey where it belongs, after the timeout-wrapped disconnect.

Also fixed a contradiction inside the branch's own code:
isValidSerializedPayload looped over every entry and rejected the whole
payload if any one was invalid, which made the per-entry
sanitizeWalletActiveKey/filter below it unreachable. Its own test
"handles invalid active keys array by sanitizing" expects one good entry
out of three to survive, so the validator now checks the envelope
(record, known version, activeKeys array) and leaves entry validity to
the sanitize step.

That alone would have silently dropped bad entries, which the sibling
test "rejects session state with missing required fields" requires a warn
for, so rehydrate now logs REHYDRATE DROPPED ENTRIES when the sanitized
count is short. Partial corruption is both survivable and visible.

lint 0 errors / tsc 0 errors / 1975 tests passing / build OK
…isconnect-persistent-caching

Implement secure persistent caching for active keys in wallet_disconnect_handler (Goldii-locks#237)
… suites

Navbar (4 conflicts): kept main's design tokens and the props its side
passes (isConnecting, providerName, networkMismatch) -- the branch's
side replaced that block with a status="connected" badge and dropped
those three -- while taking the branch's mobile fixes: relative z-10,
px-4 sm:px-6, py-3 sm:py-4, gap-2, flex-wrap, min-w-0 and shrink-0 on
the brand link and badge. That is the actual Goldii-locks#259 deliverable.

wallet_disconnect_handler (3 conflicts): the third was git aligning the
branch's disconnectWalletWithCheck body onto withWalletDisconnectLoader
again, as in Goldii-locks#357 and Goldii-locks#371. Kept main's loader body; the branch's
pendingTx warning runs before the loader is entered, and its success log
sits on the real success path. Both Goldii-locks#357's options and this branch's
pendingTx wanted the 4th parameter, so options stays 4th and pendingTx
is 5th; the one call site passing it now passes undefined for options.

The logging levels were a genuine three-way conflict. This branch (Goldii-locks#241)
moves failures to console.error carrying the Error so the stack
survives, and adds a success log. Goldii-locks#364's component suite, already on
main, asserted the old behaviour: warn on failure, and complete silence
on success.

Settled as:
  success                    console.info   (informational -- keeps
                                            Goldii-locks#364's "no warn, no error"
                                            assertion true)
  disconnect failure         console.error(tag, err)
  availability check failure console.error(tag, err)
  pending transaction        console.warn
  wallet not installed       console.warn

Updated the assertions that described the superseded levels: four
failure checks in wallet_disconnect_handler.component.test.ts moved from
warnSpy to errorSpy, and this branch's success/pending-tx counts now
account for console.info. No assertion changed what it verifies.

lint 0 errors / tsc 0 errors / 1996 tests passing / build OK
…-241-wallet-disconnect-handler-logging

Fix/issue 241 wallet disconnect handler logging
…s contract

main already carried a DisputeRaiseModal (plus app/lib/dispute_raise_modal
helpers and dispute_raise_modal_responsive.test.tsx). This branch is an
independent implementation of the same component with its own prop names
and copy, so the conflict could not be resolved by taking a side without
losing one suite or the other. Extended main's component instead:

- onSubmit alongside onConfirm, isLoading alongside isSubmitting, and
  submissionError alongside errorMessage -- all aliases, both fire.
- Dialog labelled per milestone ("Raise dispute for Milestone N"),
  heading "Raise Dispute - Milestone N", close button "Close modal".
- Character counter, aria-invalid/aria-describedby wiring, and a
  dispute-reason-error field message.
- Submit disabled while the reason is empty; a rejected onSubmit is
  caught and surfaced rather than becoming an unhandled rejection.

Field-level copy lives in the component rather than in
validateDisputeReason, because that helper's own wording (/more detail/,
/too long/) is asserted directly by its unit tests, while this branch
expects "Reason must be at least 10 characters". Both now hold.

Three assertions in the responsive suite described behaviour this branch
deliberately changes, so they were retargeted: the dialog aria-label, the
submitting button copy ("Raising Dispute…" -> "Submitting..."), and
empty-reason handling, which is now a disabled action rather than a
click-then-error. Each still verifies what it did before.

lint 0 errors / tsc 0 errors / 2035 tests passing / build OK
…e-modal-validation

Add dispute_raise_modal with validation messages and alerts (Goldii-locks#334)
…k-switcher-design-tokens

fix(Goldii-locks#317): Map dark_mode_switcher to design tokens
…k-switcher-responsive

fix(Goldii-locks#312): Add responsive sizing layouts on dark_mode_switcher
…ing-skeleton-stories

feat: add Storybook stories for LoadingSkeleton (closes Goldii-locks#281)
No textual conflict against current main -- GitHub's cached mergeability
had gone stale (it reported DIRTY where a local three-way merge is
clean), the same as on Goldii-locks#366. Merging main in here refreshes the head so
CI runs against it.

lint 0 errors / tsc 0 errors / 2035 tests passing / build OK
@drips-wave

drips-wave Bot commented Aug 31, 2026

Copy link
Copy Markdown

@She-ge Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@godamongstmen897
godamongstmen897 merged commit c11e364 into Goldii-locks:main Aug 31, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Build Storybook interface mocks for dispute_raise_modal